package com.wzw.expression.expression.config;

import com.wzw.expression.expression.annotations.EnableExpression;
import com.wzw.expression.expression.invocation.OperationInvocationCache;
import com.wzw.expression.expression.invocation.OperationInvocationContextProvider;
import com.wzw.expression.expression.invocation.OperationInvocationMetadataProvider;
import com.wzw.expression.expression.operation.AnnotationOperationProvider;
import com.wzw.expression.expression.parser.AnnotationParser;
import com.wzw.expression.expression.parser.SpringAnnotationParser;
import com.wzw.expression.expression.source.AnnotationOperationSource;
import com.wzw.expression.expression.source.OperationSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.context.annotation.Role;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;

import java.util.List;
import java.util.Objects;

/**
 * @author Wangzhiwen
 */
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ExpressionConfiguration implements ImportAware {

    private AnnotationAttributes enableExpression;

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @ConditionalOnMissingBean(SpringAnnotationParser.class)
    public AnnotationParser defaultExpressionAnnotationParser(@Autowired(required = false) List<AnnotationOperationProvider> providers) {
        SpringAnnotationParser parser = new SpringAnnotationParser();
        if (Objects.nonNull(providers) && !providers.isEmpty()) {
            providers.forEach(parser::addProvider);
        }
        return parser;
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @ConditionalOnMissingBean(AnnotationOperationSource.class)
    public OperationSource defaultExpressionOperationSource(@Autowired(required = false) List<AnnotationParser> parsers) {
        AnnotationOperationSource source = new AnnotationOperationSource();
        if (Objects.nonNull(parsers) && !parsers.isEmpty()) {
            parsers.forEach(source::addAnnotationParser);
        }
        return source;
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public OperationInvocationCache defaultOperationInvocationCache(@Autowired(required = false) List<OperationInvocationMetadataProvider> metadataProviders, @Autowired(required = false) List<OperationInvocationContextProvider> contextProviders) {
        OperationInvocationCache operationInvocationCache = new OperationInvocationCache();
        if (Objects.nonNull(metadataProviders) && !metadataProviders.isEmpty()) {
            metadataProviders.forEach(operationInvocationCache::addOperationMetadataProvider);
        }
        if (Objects.nonNull(contextProviders) && !contextProviders.isEmpty()) {
            contextProviders.forEach(operationInvocationCache::addOperationContextProvider);
        }
        return operationInvocationCache;
    }

    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        this.enableExpression = AnnotationAttributes.fromMap(importMetadata.getAnnotationAttributes(EnableExpression.class.getName()));
        if (Objects.isNull(this.enableExpression)) {
            throw new IllegalArgumentException("@EnableExpression is not present on importing class " + importMetadata.getClassName());
        }
    }
}
